#include "mainwindow.h"
#include "ui_mainwindow.h"

#include "testableAssert.h"
#include "qfile.h"
#include "qmessagebox.h"
#include "qurl.h"
#include "qmimedata.h"
#include "qshortcut.h"
#include "ApplicationIcon.h"
#include "ApplicationSettings.h"
#include "QFileInfo"


#include "ApplicationSettings.h"
#include "QVBoxLayout"

#include "LightPresetModel.h"
#include "LightEngine.h"
#include "lightControlGuiFactory.h"


/******************************  settings ******************************/
/** style of widgets that are not in docked areas */
#define CENTRAL_WIDGET_STYLE   "QWidget#centralWidget { background-color: #E0E0FA; } "

/***********************************************************************/


MainWindow::MainWindow( FileInport &fileInport,
                        ApplicationSettings & applicationSettings,
                        QWidget *parent) :
   QMainWindow(parent),
   ui(new Ui::MainWindow),
   m_fileInport(fileInport),
   m_applicationSettings(applicationSettings)
{
   ui->setupUi(this);
   setDockNestingEnabled( true);

   setWindowIcon( ApplicationIcon("starvax.png") );
   setWindowTitle( tr("Me.te.or. Player - untitled[*]") );
   setStyleSheet( QString(CENTRAL_WIDGET_STYLE));

   retrieve_gui_elements();
   setup_gui_elems();

   createRecentShowActions();
   connect( &m_applicationSettings, SIGNAL(recentShowsChanged()),
            this, SLOT(onRecentShowsChanged()) );
   connect_actions();

   load_action_icons();
   restoreState( m_applicationSettings.getPreviousWindowSetting() );
   restoreGeometry( m_applicationSettings.getPreviousWindowGeometry() );

   qApp->installTranslator( &appTranslator);
   loadApplicationLanguage();

   qApp->setApplicationVersion( QString("%1 - %2").arg(__DATE__).arg(__TIME__));
}

MainWindow::~MainWindow()
{
   delete ui;
}

void MainWindow::retrieve_gui_elements()
{
   ui_volumeBarLayout = ui->volumeSliderLayout;

   ui_script_anim_toolbar = findChild<QToolBar *>("script_anim_toolbar");
   ui_script_toolbar = findChild<QToolBar *>("script_toolbar");
   ui_music_toolbar = findChild<QToolBar *>("music_toolbar");
}

/** gracefully close all active services */
void MainWindow::closeEvent(QCloseEvent *ev)
{
   m_applicationSettings.saveWindowSetting( saveState());
   m_applicationSettings.saveWindowGeometry( saveGeometry());

   emit mainWindowAboutToClose();

   if (isWindowModified())
   {
      if (askToSave() != QMessageBox::Cancel)
      {
         QMainWindow::closeEvent(ev);
      }
      else
      {
         ev->ignore();
      }
   }
}

int MainWindow::askToSave()
{
   int res = QMessageBox::question( this, tr("save before exit"),
                                    tr("The show has changed. Do you want to save it?"),
                                    QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel);

   if (res == QMessageBox::Yes)
   {
      if (windowTitle().startsWith("Me.te.or. Player - untitled"))
      {
         emit saveShowAsTriggered();
      }
      else
      {
         emit saveShowTriggered();
      }
   }

   return res;
}

void MainWindow::openApplicationArguments()
{
   /* every argument passed when launching application
    * must be a file to be opened
    */
   for( int i = 1; i < qApp->arguments().count(); i++ )
   {
      m_fileInport.openFile( qApp->arguments().at(i) );
   }
}

void MainWindow::loadApplicationLanguage()
{
   ApplicationSettings::Language storedLanguage;
   storedLanguage = m_applicationSettings.language();
   bool isLocaleSelected = (storedLanguage == ApplicationSettings::LOCALE);

   ui->actionLocale->setChecked( isLocaleSelected);
   on_actionLocale_triggered( isLocaleSelected);
}

/************************************************/
/* setup_gui_elems                              */
/*  setup gui elements and utils                */
/************************************************/
void MainWindow::setup_gui_elems()
{
   // give viewer and playlist a proper space ratio
   setup_drop_function();

   // file input routing
   connect( &m_fileInport, SIGNAL(loadStyle(QString)),
            this, SLOT(loadStyleSheet(QString)) );

}

void MainWindow::setup_drop_function()
{
   /* all drop operations are managed by main window */
   ui->dockPlaylist->setAcceptDrops( false);
   ui->dockLightPanel->setAcceptDrops( false);
   ui->dockSequence->setAcceptDrops( false);
   ui->scriptArea->setAcceptDrops( false);

   setAcceptDrops( true );
}

void MainWindow::createRecentShowActions()
{
   ui->menuFile->addSeparator();

   for (int i = 0; i < m_applicationSettings.maxRecentShowFiles(); ++i)
   {
      QAction * recentShowAction = new QAction(this);
      recentShowAction->setVisible( false);
      m_recentShowActions.append( recentShowAction);

      connect( recentShowAction, SIGNAL(triggered()),
               this, SLOT(openRecentShow()));
   }

   /* add to menu */
   ui->menuFile->addActions( m_recentShowActions);

   /* load shows of previous sessions */
   onRecentShowsChanged();
}


void MainWindow::connect_actions()
{
   connect( ui->action_Save_Show, SIGNAL(triggered()), this, SIGNAL(saveShowTriggered()) );
   connect( ui->action_Save_Show_As, SIGNAL(triggered()), this, SIGNAL(saveShowAsTriggered()) );
   connect( ui->action_Open_Show, SIGNAL(triggered()), this, SIGNAL(openShowTriggered()) );

   connect( ui->action_Open_script, SIGNAL(triggered()),
            &m_fileInport, SLOT(openScriptDialog()) );
   connect( ui->action_Open_music, SIGNAL(triggered()),
            &m_fileInport, SLOT(openTracksDialog()) );

   ui->action_Save_Show->setEnabled( false);
   ui->action_Save_Show_As->setEnabled( true);
}

void MainWindow::load_action_icons()
{
   attachIcon( ui->action_Open_script, "open_script.png" );
   attachIcon( ui->action_Open_music, "open_music.png" );

   attachIcon( ui->actionOpenCurtain, "openCurtain.png" );
   attachIcon( ui->actionCloseCurtain, "closeCurtain.png" );

   attachIcon( ui->action_Open_Show, "open_show.png" );
   attachIcon( ui->action_Save_Show, "save_show.png" );
   attachIcon( ui->action_Dark_Mode, "dark_mode.png" );

   attachIcon( ui->actionAbout_MeTeOr_Player, "starvax.png");
}

void MainWindow::attachIcon( QAction *action, const QString &icon_filename)
{
   action->setIcon( ApplicationIcon( icon_filename ) );
}


QWidget *MainWindow::sequenceFunctionArea()
{
   return ui->dockSequence;
}

QWidget *MainWindow::scriptArea()
{
   return ui->scriptArea;
}

QLayout *MainWindow::playlistArea()
{
   Q_ASSERT( ui->dockPlaylist->layout() != NULL);
   return ui->dockPlaylist->layout();
}

QLayout *MainWindow::lightControlArea()
{
   Q_ASSERT( ui->dockLightPanel->layout() != NULL);
   return ui->dockLightPanel->layout();
}

QBoxLayout *MainWindow::volumeSliderArea()
{
   return ui->volumeSliderLayout;
}

void MainWindow::setMediaListActions(QList<QAction *> &actions)
{
   ui->menu_Music->addActions( actions);

   foreach (QAction *action, actions)
   {
      if (! action->icon().isNull())
      {
         ui->music_toolbar->insertAction( NULL, action);
      }
   }
}

void MainWindow::setLightControlActions(QList<QAction *> &actions)
{
   ui->menu_Ligth->addActions( actions);
}

void MainWindow::setSequenceActions(QList<QAction *> &actions)
{
   ui->menu_Sequence->addActions( actions);
}

void MainWindow::setScriptActions( const QList<QAction *> &actions)
{
   ui->menu_Script->addActions( actions);
   ui->script_anim_toolbar->addActions( actions);
}

void MainWindow::onShowNameChanged(const QString &filename)
{
   setWindowTitle( QString("Me.te.or. Player - %1[*]").arg(filename) );
   ui->action_Save_Show->setEnabled( false );
   setWindowModified( false);
}

/**
 * called when any element of the show changes
 */
void MainWindow::onShowChanged()
{
   ui->action_Save_Show->setEnabled( true );
   setWindowModified( true );
}

/**
 * callback when the show is saved
 */
void MainWindow::onShowSaved( const QString & showPath)
{
   onShowNameChanged( showPath);
   ui->action_Save_Show->setEnabled( false );
   setWindowModified( false );
}

/************************************************/
/* dragEnterEvent                               */
/*  callback when anything is dropped into main */
/*  window (no matter which pane)               */
/************************************************/
void MainWindow::dragEnterEvent ( QDragEnterEvent * e )
{
   // The only accepted mime type is a file url
   if( e->mimeData()->hasUrls() )
   {
      e->acceptProposedAction();
   }
}

/************************************************/
/* dropEvent                                    */
/*  callback when valid mime is dropped into    */
/*  main window (no matter which pane)          */
/************************************************/
void MainWindow::dropEvent ( QDropEvent * e )
{
   // mime data are expected to be url
   foreach( QUrl url, e->mimeData()->urls())
   {
      m_fileInport.openFile( url.toLocalFile() );
   }

   // accepted action
   e->acceptProposedAction();
}

/************************************************/
/* on_actionAbout_MeTeOr_Player_triggered       */
/*  show about box                              */
/************************************************/
void MainWindow::on_actionAbout_MeTeOr_Player_triggered()
{
   QMessageBox::about( this, tr("About Starvax Me.Te.Or. Player"),
                       QString("<h2>Starvax Me.Te.Or. Player</h2>") +
                       QString("<h3><i>Build %1.%2.%3</i></h3>  %4").
                       arg(VERSION_MAJOR).arg(VERSION_MINOR).arg(VERSION_BUILD)
                       .arg(qApp->applicationVersion()) +
                       tr("<p>Custom script, music and light animation for Me.Te.Or Shows.<br/>") +
                       QString("Powered by <b><a href=\"http://qt-project.org/\">QT5</b>.</p>") );
}

/************************************************/
/* on_actionLocale_triggered                    */
/*  callback when local language is required    */
/************************************************/
void MainWindow::on_actionLocale_triggered(bool checked)
{
   if( checked )
   {
      // retranslate to local language
      appTranslator.load( "player_it",
                          qApp->applicationDirPath() + "/res/translations" );
      m_applicationSettings.setLanguage( ApplicationSettings::LOCALE);
   }
   else
   {
      // retranslate to native language.
      appTranslator.load( QString(), QString() );
      m_applicationSettings.setLanguage( ApplicationSettings::NATIVE);
   }

   ui->retranslateUi( this );
}

/************************************************/
/* on_action_Dark_Mode_triggered                */
/*  switch between a default style and custom   */
/*  style                                       */
/************************************************/
void MainWindow::on_action_Dark_Mode_triggered(bool checked)
{
   if( checked )
   {
      QString style = FileInport::open_style_dialog();

      if( style != QString() )
      {
         loadStyleSheet( style );
      }
      else
      {
         // do not check menu entry
         ui->action_Dark_Mode->setChecked( false );
      }
   }
   else
   {
      // default aspect
      qApp->setStyleSheet("");
   }
}

void MainWindow::loadStyleSheet(const QString &filename)
{
   QFile fStyle( filename );
   fStyle.open( QIODevice::ReadOnly );

   qApp->setStyleSheet( fStyle.readAll() );
   fStyle.close();

   ui->action_Dark_Mode->setChecked( true );
}

void MainWindow::onRecentShowsChanged()
{
   QStringList showFiles = m_applicationSettings.recentShowFiles();

   int numRecentFiles = qMin(showFiles.size(), m_recentShowActions.size());

   for (int i = 0; i < numRecentFiles; ++i)
   {
      QString text = tr("&%1 %2").arg(i + 1).arg( showFiles[i]);
      m_recentShowActions[i]->setText(text);
      m_recentShowActions[i]->setData( showFiles[i]);
      m_recentShowActions[i]->setVisible(true);
   }

   for (int i = numRecentFiles; i < m_recentShowActions.size(); ++i)
   {
      T_ASSERT_REP ( i < m_recentShowActions.size(), "MW: invalid index");
      m_recentShowActions[i]->setVisible(false);
   }
}

void MainWindow::openRecentShow()
{
   QAction *action = qobject_cast<QAction *>(sender());
   if (action != NULL)
   {
      QString filePath( action->data().toString());

      if (QFileInfo(filePath).exists())
      {
         emit loadShowFile( action->data().toString() );
      }
      else
      {
         m_applicationSettings.removeRecentShowFile( filePath);
      }
   }
}

void MainWindow::on_actionOpenCurtain_triggered()
{
   QMessageBox msg(QMessageBox::NoIcon, tr("OPEN CURTAIN - Not yet implemented"),
                   tr("In order to open the curtain a motor is needed.\n"
                      "This action is not yet possible"));
   msg.setIconPixmap( QPixmap(IconPath("openCurtain.png")) );

   msg.exec();
}

void MainWindow::on_actionCloseCurtain_triggered()
{
   QMessageBox msg(QMessageBox::NoIcon, tr("CLOSE CURTAIN - Not yet implemented"),
                   tr("In order to close the curtain a motor is needed.\n"
                      "This action is not yet possible"));
   msg.setIconPixmap( QPixmap(IconPath("closeCurtain.png")) );

   msg.exec();
}

